Skip to content

Conversation

@aponcedeleonch
Copy link
Member

@aponcedeleonch aponcedeleonch commented Dec 23, 2025

Closes: #210

Summary

  • Renamed determine_proxy_mode to determine_transport_type with runtime_mode parameter
  • Docker mode: checks proxy_mode field (how proxy connects to container)
  • K8s mode: checks transport_type field (direct connection to pod)
  • Both modes fall back to URL detection if primary field not set
  • Added runtime_mode parameter to MCPServerClient constructor (defaults to "docker")
  • Updated call sites in ingestion.py and server.py to pass runtime_mode
  • Added explanatory comments about runtime-specific transport determination
  • Renamed ToolHiveProxyMode to ToolHiveTransportMode for consistency
  • Updated function name from url_to_toolhive_proxy_mode to url_to_toolhive_transport_mode

🤖 Generated with Claude Code

@claude
Copy link

claude bot commented Dec 23, 2025

PR Review: Refactor transport type handling and remove URL normalization

Summary

This PR successfully refactors transport type handling by renaming ToolHiveProxyMode to ToolHiveTransportType and extracting transport type determination logic into a reusable function. The removal of URL normalization simplifies the codebase significantly.

✅ Positives

  • Clear separation of concerns: determine_transport_type() is now a standalone function that can be easily tested and reused
  • Simpler flow: Removal of URL normalization reduces complexity - URLs are now used as-is
  • Better naming: ToolHiveTransportType is more descriptive than ToolHiveProxyMode
  • Proper fallback chain: transport_type → proxy_mode → URL detection is logical
  • Tests updated correctly: All test files reflect the changes appropriately

🐛 Issues Found

1. Duplicate code in determine_transport_type() (mcp_client.py:44-70)

Lines 44-53 and 62-70 are nearly identical. Consider extracting to a helper:

def _parse_transport_string(value: str) -> ToolHiveTransportType | None:
    lower = value.lower()
    if lower == "streamable-http":
        return ToolHiveTransportType.STREAMABLE
    elif lower == "sse":
        return ToolHiveTransportType.SSE
    return None

2. Inconsistent error handling (mcp_client.py:27)

Docstring says it raises WorkloadConnectionError but function never raises it - only returns defaults or fallback values. Either:

  • Update docstring to remove the exception
  • Actually raise exception for invalid/unknown transport types

3. Missing return type annotation (ingestion.py:676)

determine_transport_type() returns ToolHiveTransportType but it's cast to TransportType. The cast seems unnecessary - clarify the relationship between these types or fix the return type.

4. Outdated docstring (toolhive/enums.py:5-7)

Still says "Enum for ToolHive proxy modes" but should say "Enum for ToolHive transport types"

5. Verbose logging (mcp_client.py:40-53, 58-70)

Multiple debug/warning logs with f-strings in determine_transport_type(). Consider reducing verbosity or moving some to trace level.

💡 Suggestions

Performance

  • ingestion.py:989-999: Consider whether all 9 fields need logging for every workload. This could be noisy at scale.

Code clarity

  • mcp_client.py:211: Typo fix for import - streamable_http_client ✓ (already fixed)
  • ingestion.py:18: Good that DuplicateRegistryServersError import moved to top level

⚠️ Minor Concerns

  • Helm chart changelog removed (Chart.yaml:17-19) - is this intentional? Version history is useful for operators.
  • Test coverage reduced: removed test_map_transport_type_* tests but no new tests for determine_transport_type() function

🔒 Security & Breaking Changes

  • No security concerns identified
  • Breaking change: Any code directly calling ToolHiveProxyMode or url_to_toolhive_proxy_mode() will break (acceptable for internal refactor)

Overall: Clean refactor with good simplification. Address the code duplication and docstring issues for better maintainability.

@aponcedeleonch
Copy link
Member Author

@claude check if your comments were addressed

@claude
Copy link

claude bot commented Dec 23, 2025

Claude finished @aponcedeleonch's task —— View job


Review Comments Status Check

I've reviewed the current state of the code to see if the issues from my previous review were addressed.


Issue #1: Duplicate code in determine_transport_type()RESOLVED

Status: The duplicate code has been removed! The function is now much cleaner and simpler.

What changed:

  • Lines 27-65 in mcp_client.py show the refactored function
  • The old approach with proxy_mode field fallback has been removed
  • Function now checks transport_type field, then falls back to URL-based detection
  • Much cleaner implementation without duplication

Issue #2: Inconsistent error handlingRESOLVED

Status: Fixed! The function now properly raises WorkloadConnectionError.

What changed:

  • Lines 57-59 in mcp_client.py now raise WorkloadConnectionError when no transport type or URL is available
  • Docstring at lines 34-35 correctly documents this exception
  • Consistent error handling throughout

Issue #3: Missing return type annotationRESOLVED

Status: Fixed! The function is properly annotated.

What changed:

  • Line 27 in mcp_client.py: def determine_transport_type(workload: Workload) -> ToolHiveTransportType:
  • Line 677 in ingestion.py: Uses proper cast to TransportType when needed for DB operations
  • The relationship between ToolHiveTransportType (for logic) and TransportType (for DB) is now clear

Issue #4: Outdated docstringRESOLVED

Status: Fixed! The docstring now correctly describes transport types.

What changed:

  • Lines 5-7 in toolhive/enums.py now say: "Enum for ToolHive transport types. Transport types represent the MCP transport type in which ToolHive's operates for a workload."
  • Accurate and descriptive

Issue #5: Verbose loggingIMPROVED

Status: Significantly improved. The function now has much less logging.

What changed:

  • Lines 40-53 in mcp_client.py show reduced logging
  • Only 2 debug logs and 1 warning log remain (down from many more)
  • More focused and less noisy

Additional Suggestions:

Performance (logging at ingestion.py:990-1000): ⚠️ STILL PRESENT

  • Lines 990-1000 still log 9 fields per workload processing
  • This could be noisy at scale, but it's useful for debugging
  • Not a blocker, just something to monitor

Helm chart changelog: ℹ️ CONFIRMED INTENTIONAL

  • Chart version bumped to 0.2.1
  • Changelog removal appears intentional for this minor version

Test coverage: ℹ️ NOTED

  • No new tests added for determine_transport_type() function
  • Existing tests in test_mcp_client.py have been updated
  • Would be good to have explicit tests for the new function, but existing coverage may be sufficient

Summary

All 5 main issues from the previous review have been addressed!

The code quality has significantly improved:

  • No more code duplication
  • Consistent error handling with proper exceptions
  • Correct type annotations
  • Accurate documentation
  • Reduced logging verbosity

The refactoring successfully simplified the transport type handling while maintaining functionality. Great work! 🎉


Job Run | Branch: fix-sse-k8s

therealnb
therealnb previously approved these changes Jan 2, 2026
Copy link
Collaborator

@therealnb therealnb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

- Renamed determine_proxy_mode to determine_transport_type with runtime_mode parameter
- Docker mode: checks proxy_mode field (how proxy connects to container)
- K8s mode: checks transport_type field (direct connection to pod)
- Both modes fall back to URL detection if primary field not set
- Added runtime_mode parameter to MCPServerClient constructor (defaults to "docker")
- Updated call sites in ingestion.py and server.py to pass runtime_mode
- Added explanatory comments about runtime-specific transport determination
- Renamed ToolHiveProxyMode to ToolHiveTransportMode for consistency
- Updated function name from url_to_toolhive_proxy_mode to url_to_toolhive_transport_mode
- Added 7 new tests for k8s mode and cross-mode validation
- All 300 tests passing with proper runtime mode separation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@aponcedeleonch
Copy link
Member Author

@claude check my most recent changes. Look carefully for breaking changes

@claude
Copy link

claude bot commented Jan 2, 2026

Claude finished @aponcedeleonch's task —— View job


Breaking Changes Review

I've reviewed the most recent changes in this PR with a focus on identifying breaking changes.


✅ GOOD NEWS: No Breaking Changes for External Users

The changes in this PR are internal refactorings that don't break the public API:

  1. Renamed classes/functions are internal-only:

    • ToolHiveProxyModeToolHiveTransportMode
    • url_to_toolhive_proxy_mode()url_to_toolhive_transport_mode()
    • These are only used internally within mcp_optimizer package
    • No usage found in examples or external-facing code
  2. New parameter has safe default:

    • MCPServerClient.__init__() now takes runtime_mode parameter
    • BUT: It defaults to "docker" (line 104 in mcp_client.py)
    • This means existing code calling MCPServerClient(workload, timeout) will continue to work
  3. Removed internal method:

    • IngestionService._map_transport_type() was removed
    • This is a private method (underscore prefix) and shouldn't be called externally

⚠️ Internal Breaking Changes (Intentional)

These changes will break internal code that directly imports these items:

Change Type Old Name New Name Impact
Class rename ToolHiveProxyMode ToolHiveTransportMode Internal only - no external usage found
Function rename url_to_toolhive_proxy_mode() url_to_toolhive_transport_mode() Internal only - not imported externally
Private method removed _map_transport_type() determine_transport_type() Private method - moved to module level

Why this is OK:

  • All imports within the codebase have been updated
  • No external code in examples/ uses these
  • No public API documented in README uses these

🔍 Detailed Review

1. MCPServerClient Constructor Change ✅ SAFE

# OLD (origin/main)
def __init__(self, workload: Workload, timeout: float):

# NEW (this PR)  
def __init__(self, workload: Workload, timeout: float, runtime_mode: str = "docker"):

Why it's safe:

  • New parameter has a default value ("docker")
  • All internal call sites updated (ingestion.py:980, server.py:549)
  • Tests updated to pass the parameter
  • External code can continue calling without the parameter

2. Enum Rename ⚠️ INTERNAL BREAKING

# OLD: ToolHiveProxyMode
# NEW: ToolHiveTransportMode

Analysis:

  • Checked all Python files with grep -r "ToolHiveProxyMode"
  • Only found in toolhive/enums.py and mcp_client.py
  • No external usage found
  • All internal imports updated correctly

3. Function Rename ⚠️ INTERNAL BREAKING

# OLD: url_to_toolhive_proxy_mode()
# NEW: url_to_toolhive_transport_mode()

Analysis:

  • Checked all files with grep -r "url_to_toolhive_proxy_mode"
  • No matches found - function not called anywhere now
  • Only used internally within determine_transport_type()

4. Removed Method ⚠️ INTERNAL BREAKING

# REMOVED: IngestionService._map_transport_type()
# REPLACED WITH: determine_transport_type() (module-level function)

Why it's safe:

  • Method was private (underscore prefix)
  • Replaced with better module-level function
  • All call sites updated (ingestion.py:677)

✅ Summary

For external users: ✨ NO BREAKING CHANGES

  • The MCP Optimizer server API is unchanged
  • Example code will continue to work
  • CLI interface unchanged

For internal code: Changes are intentional refactoring

  • All internal imports have been updated
  • Tests updated and passing
  • Better separation of concerns with determine_transport_type() as a standalone function

Recommendation: 👍 Safe to merge - This is a clean refactoring with no external API breakage.


Job Run | Branch: fix-sse-k8s

Copy link
Collaborator

@therealnb therealnb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

@aponcedeleonch aponcedeleonch merged commit f12db02 into main Jan 2, 2026
8 checks passed
@aponcedeleonch aponcedeleonch deleted the fix-sse-k8s branch January 2, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimizer is trying to use streamable-http for SSE servers in Kubernetes

3 participants